package util

import (
	"sort"
	"strings"
	"sync"
)

type Rule struct {
	V1      []string
	V2      []string
	Count   int
	Support float64
}

type task struct {
	i int
	j int
}
type ItemsAndCount struct {
	Items []string //频繁数据
	Count int
}

func CalculateStrongRules1(all [][]*ItemsAndCount, r float64) []*Rule {
	var ch = make(chan task, 1<<12)
	var wg = sync.WaitGroup{}
	var mps = make([]map[string]float64, len(all))
	var ch1 = make(chan int, len(all))
	var mutex = &sync.Mutex{}
	var rules = make([]*Rule, 0)
	for i := 0; i < len(all); i++ {
		wg.Add(1)
		ch1 <- i
	}
	close(ch1)
	for i := 0; i < 12; i++ {
		go func() {
			for i1 := range ch1 {
				var mp = make(map[string]float64, len(all[i1]))
				var sb = strings.Builder{}
				for j := 0; j < len(all[i1]); j++ {
					sort.Strings(all[i1][j].Items)
					for k := 0; k < len(all[i1][j].Items); k++ {
						sb.WriteString(all[i1][j].Items[k])
						sb.WriteByte('|')
					}
					mp[sb.String()] = float64(all[i1][j].Count)
					sb.Reset()
				}
				mps[i1] = mp
				wg.Done()
			}
		}()
	}
	wg.Wait()
	wg.Add(1)
	go func() {
		for i := 1; i < len(all); i++ {
			for j := 0; j < len(all[i]); j++ {
				wg.Add(1)
				ch <- task{
					i: i,
					j: j,
				}
			}
		}
		close(ch)
		wg.Done()
	}()
	for i := 0; i < 12; i++ {
		go func() {
			var s1 = make([]string, len(all))
			var s2 = make([]string, len(all))
			var st1, st2 = 0, 0
			var sb = strings.Builder{}
			for task := range ch {
				len1 := task.i + 1
				max := (1 << len1) / 2
				for mask := 1; mask < max; mask++ {
					st1, st2 = 0, 0
					for k := 0; k < len1; k++ {
						if mask&(1<<k) != 0 {
							s1[st1] = all[task.i][task.j].Items[k]
							st1++
						} else {
							s2[st2] = all[task.i][task.j].Items[k]
							st2++
						}
					}
					for k := 0; k < st1; k++ {
						sb.WriteString(s1[k])
						sb.WriteByte('|')
					}
					str1 := sb.String()
					sb.Reset()
					for k := 0; k < st2; k++ {
						sb.WriteString(s2[k])
						sb.WriteByte('|')
					}
					str2 := sb.String()
					sb.Reset()
					if float64(all[task.i][task.j].Count)/mps[st1-1][str1] >= r {
						mutex.Lock()
						rules = append(rules, &Rule{
							V1:      []string{str1},
							V2:      []string{str2},
							Count:   0,
							Support: float64(all[task.i][task.j].Count) / mps[st1-1][str1],
						})
						mutex.Unlock()
					}
					if float64(all[task.i][task.j].Count)/mps[st2-1][str2] >= r {
						mutex.Lock()
						rules = append(rules, &Rule{
							V1:      []string{str2},
							V2:      []string{str1},
							Count:   0,
							Support: float64(all[task.i][task.j].Count) / mps[st2-1][str2],
						})
						mutex.Unlock()
					}
				}
				wg.Done()
			}
		}()
	}
	wg.Wait()
	return rules
}
